function TravelAction(travelSteps, dateRange) {
    this._travelSteps = travelSteps;
    this._travelStepsToAdd = travelSteps.add;
    this._travelStepsToRemove = travelSteps.remove;
    this._dateRange = dateRange;
}

TravelAction.prototype = {
    hasConflict: function(repository) {
        var travelSteps = this._getTravelStepsWithoutDeletingOnes(repository);
        return new TravelConflicts(this._travelStepsToAdd).detectConflicts(travelSteps);
    },

    apply: function(repository, recordHistoryCallback) {
        this._addTidForNewTravelSteps();
        var applicableMonths = repository.getApplicableMonths(this._dateRange);

        recordHistoryCallback(applicableMonths, { remove: this._travelStepsToAdd, add: this._travelStepsToRemove});
        this._updateLocations(this._travelStepsToAdd, repository);
        repository.saveTravelSteps(this._travelSteps);
    },

    applyUI: function(calendarViewBody) {
        calendarViewBody.updateLocations();
    },
    _addTidForNewTravelSteps : function() {
        this._travelStepsToAdd.foreach(function(travelStep) {
            ///TODO: get GUIDs from server
            travelStep.setId($.Guid.New());
        });
    },

    _getTravelStepsWithoutDeletingOnes: function(repository) {
        var from = this._dateRange.start.getFullYear();
        var to = this._dateRange.end.getFullYear();

        var travelSteps = repository.getTravelStepsInRange(from, to);
        this._travelStepsToRemove.foreach(function(stepToRemove) {
            travelSteps = TravelStep.removeTravelStep(stepToRemove, travelSteps);
        });
        return travelSteps;
    },

    _updateLocations: function(travelSteps, repository) {
        this._updateLocationBetweenTravels(travelSteps, repository);
        this._updateLocationOnTravelDays(travelSteps, repository);
    },

    _updateLocationOnTravelDays: function(travelSteps, repository) {
        var me = this;
        travelSteps.foreach(function(step) {
            var dateRange = step.getDateRange();
            var months = repository.getApplicableMonths(dateRange);
            months.foreach(function(month) {
                me._clearLocationForMonth(month, dateRange);
            });
            repository.markAsChanged(months);
        });
    },

    _updateLocationBetweenTravels: function(travelSteps, repository) {
        var me = this;
        travelSteps.foreach(function(step, i) {
            if (i == 0) {
                return;
            }
            me._updateLocationBetweenTravelSteps(travelSteps[i - 1], step, repository);
        });
    },

    _updateLocationBetweenTravelSteps: function(previousStep, currentStep, repository) {
        var me = this;
        var startDate = previousStep.getArrivalDate().clone().addDays(1);
        var endDate = currentStep.getDepartureDate().clone().addDays(-1);

        if (startDate > endDate) {
            return;
        }

        var location = currentStep.getDepartureLocation();
        var dateRange = new DateRange(startDate, endDate);
        var months = repository.getApplicableMonths(dateRange);

        months.foreach(function(month) {
            me._applyLocationToMonth(month, location, dateRange);
        });
        repository.markAsChanged(months);
    },


    _clearLocationForMonth: function(month, dateRange) {
        month.eachDay(function(currentDay) {
            if (dateRange.containsDate(currentDay.getDate())) {
                currentDay.setLocation(null);
            }
        });
    },

    _applyLocationToMonth: function(month, location, dateRange) {
        month.eachDay(function(currentDay) {
            if (dateRange.containsDate(currentDay.getDate()) && !currentDay.hasTravel()) {
                 currentDay.setLocation(location);
            }
        });
    }
};
